﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Expect.Core.Errors;
using Expect.Core.BaseClasses;

namespace Expect.Core
{
    using System.Diagnostics;

    using Expect.Core.IO;

    /// <summary>
    /// Represent a row of a fixture
    /// </summary>
    [DebuggerDisplay("{RowAsText}:{IsSuccessful}")]
    [Serializable]
    public class FixtureRow : RunnableList<FixtureCell>
    {
        /// <summary>
        /// Row meta data
        /// </summary>
        public ParsingMetaData MetaData { get; internal set; }
        
        /// <summary>
        /// Row representation
        /// </summary>
        public string RowAsText
        {
            get
            {
                StringBuilder sb = new StringBuilder();
                foreach (var cell in Cells)
                {
                    if (sb.Length > 0) sb.Append(" | ");
                    sb.Append(cell.DisplayText);
                }
                return sb.ToString();
            }
        }
        /// <summary>
        /// List of the cells of the row
        /// </summary>
        public IList<FixtureCell> Cells
        {
            get { return ChildElements; }
        }

        #region Constructors
        /// <summary>
        /// Constructor
        /// </summary>
        public FixtureRow()
        {            
        }

        /// <summary>
        /// Constructor that create cells from cells's text
        /// </summary>
        /// <param name="cellsText"></param>
        public FixtureRow(string[] cellsText)
        {
            foreach(string s in cellsText)
            {
                AddCell(s);
            }
        }
        #endregion        

        /// <summary>
        /// Add a cell with the provided text
        /// </summary>
        /// <param name="txt"></param>
        public FixtureCell AddCell(string txt)
        {
            FixtureCell cell = new FixtureCell {Text = txt};
            Cells.Add(cell);
            return cell;
        }

        /// <summary>
        /// Add a cell with the provided expected value
        /// </summary>
        /// <param name="expectedValue"></param>
        public FixtureCell AddCell(object expectedValue)
        {
            FixtureCell cell = new FixtureCell {ExpectedValue = expectedValue, Text = expectedValue.ToString()};
            Cells.Add(cell);
            return cell;
        }

        /// <summary>
        /// Get an array from cells text, starting at the provided cell index
        /// </summary>
        /// <param name="fromIndex">index of the first cell to pick for building the array</param>
        /// <returns>An array of cell's text</returns>
        public string[] GetArray(int fromIndex)
        {
            string[] res = new string[Count - fromIndex];
            for (int i=fromIndex; i<Count ; i++)
            {
                res[i-fromIndex] = this[i].Text;
            }
            return res;
        }

        /// <summary>
        /// Return a header to put in error messages for this element
        /// </summary>
        /// <returns></returns>
        protected override string ElementErrorHeader()
        {
            if (!Status.Success.HasValue)
            {
                return string.Format("The row was not properly resolved : {0}", RowAsText);
            }
            else if (!Status.Success.Value)
            {
                return string.Format("Row failed : {0}", RowAsText);
            }

            return string.Empty;
        }

        internal RowData GetRowData(List<string> definition)
        {
            RowData res = new RowData();
            
            for(int i = 0 ; i< definition.Count ; i++)
            {
                if (Cells.Count >= definition.Count)
                    res.Add(definition[i], Cells[i].Text);
            }

            return res;
        }

        /// <summary>
        /// List of names for fluent style fixtures (1 cell out of 2)
        /// </summary>
        /// <returns></returns>
        public IEnumerable<string> NamesForFluent()
        {
            for (int i = 0; i < Cells.Count; i++ )
            {
                if (i % 2 == 0) yield return Cells[i].Text;
            }
        }

        /// <summary>
        /// List of arguments for fluent style fixtures (1 cell out of 2)
        /// </summary>
        /// <returns></returns>
        public IEnumerable<string> ArgsForFluent()
        {
            for (int i = 0; i < Cells.Count; i++)
            {
                if (i % 2 != 0 && !string.IsNullOrEmpty(Cells[i].Text))
                {
                    yield return Cells[i].Text;
                }
            }
        }

        /// <summary>
        /// Return row as plain text
        /// </summary>
        /// <returns></returns>
        public string AsText()
        {
            StringBuilder builder = new StringBuilder();

            foreach (var cell in Cells)
            {
                if (builder.Length > 0) builder.Append(" ");
                builder.Append(cell.Text);
            }

            return builder.ToString();
        }
    }
}
